package com.seeyon.apps.cfca.manager;

import cfca.paperless.ClientConstants;
import cfca.paperless.base.BaseConstants;
import cfca.paperless.base.util.GUIDUtil;
import cfca.paperless.base.util.IoUtil;
import cfca.paperless.base.util.PwdEncryptUtil;
import cfca.paperless.base.util.StringUtil;
import cfca.paperless.client.PaperlessClient;
import cfca.paperless.dto.RequestHead;
import cfca.paperless.dto.ResponseDto;
import cfca.paperless.dto.ResponseHead;
import cfca.paperless.dto.bean.SealStrategy;
import cfca.paperless.dto.request.requestbody.tx40.SealPdfRequestBody;
import cfca.paperless.dto.request.tx40.SealPdfRequest;
import cfca.paperless.dto.response.responsebody.tx40.SealPdfResponseBody;
import cfca.paperless.dto.response.tx40.SealPdfResponse;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.seeyon.apps.cfca.PaperlessConfig;
import com.seeyon.apps.cfca.tools.MD5;
import com.seeyon.apps.cfca.tools.OkHttp3Util;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 *
 * @Description: PDF签章-机构章-使用印章绑定图片签章-坐标签章 、 空白域签章、关键字签章
 * @author: zf
 * @date: 2019年6月25日 上午11:59:18
 */
@Service
@Slf4j
public class SealPdfMessageImpl implements SealPdfMessage {

    /**
     *
     * @Description: 签章
     * @throws Exception
     * @return: void
     */
    @Override
    public JSONObject doWork(String functionName , String sealPerson , byte[] pdfByte) throws Exception {

        PaperlessClient paperlessClient = new PaperlessClient(PaperlessConfig.host, PaperlessConfig.port, 3000, 20000);

        paperlessClient.setSSL(false);
        paperlessClient.setSslProtocol(PaperlessConfig.sslProtocol);
        paperlessClient.setKeyStorePath(PaperlessConfig.keyStorePath);
        paperlessClient.setKeyStorePassword(PaperlessConfig.keyStorePassword);
        paperlessClient.setTrustStorePath(PaperlessConfig.trustStorePath);
        paperlessClient.setTrustStorePassword(PaperlessConfig.trustStorePassword);
        /*******************************************************************************/
        // 构造请求对象
        SealPdfRequest sealPdfRequest = new SealPdfRequest();
        RequestHead requestHead = new RequestHead();
        // 业务流水号 非空
        String transactionNo = GUIDUtil.generateId();
        // 机构编码非空
        String organizationCode = PaperlessConfig.organizationCode;
        // 操作员编码 可为空
        String operatorCode = PaperlessConfig.operationCode;
        // 渠道编码 可为空
        String channelCode = PaperlessConfig.channelCode;
        // 设置属性
        requestHead.setBasicInfo(transactionNo, organizationCode, operatorCode, channelCode);

        sealPdfRequest.setHead(requestHead);
        /*******************************************************************************/
        SealPdfRequestBody requestBody = new SealPdfRequestBody();
        // 数据源类型 1 pdf文件路径 2 pdf文件字节流
        String inputType = BaseConstants.INPUT_TYPE_FILEDATA;
        // 设置数据源，数据源类型为2时，为空，数据源类型为1时，上送数据源路径（服务器可以访问到的文件路径）
        // 待签章文件
        //requestBody.setInputSource();
        //inputType=2 时非空
        requestBody.setPdfData(pdfByte);
        // 数据源类型
        requestBody.setInputType(inputType);
        // 签章后文件保存地址，不为空时，直接将签章文件保存在此地址，不再返回签章后文档数据
        requestBody.setOutputFilepath("");
        // 时间戳方式，默认为0；0：实时访问CFCA 时间戳服务；1：使用从CFCA购置并在本地部署的时间戳服务器产品；
        requestBody.setTimestampChannel(BaseConstants.TIME_STAMP_CHANNEL_CFCA);

        //所属业务类型编码 需要在Manager上先维护业务类型 可为空
        requestBody.setBizTypeCode("");

        /************************ 构造机构章策略 ********************************************/
        SealStrategy sealStrategy = generateSealStrategy(sealPerson);

        requestBody.setSealStrategy(sealStrategy);

        sealPdfRequest.setBody(requestBody);

        /************************ 请求签章 ********************************************/

        log.info("开始签章");
        ResponseDto responseDto = paperlessClient.execute(sealPdfRequest);
        log.info("签章结束");

        /************************ 解析响应结果 *********************************/

        SealPdfResponse sealPdfResponse = (SealPdfResponse) responseDto;

        ResponseHead responseHead = sealPdfResponse.getHead();
        SealPdfResponseBody responseBody = sealPdfResponse.getBody();

        if (ClientConstants.CODE_SUCCESS.equals(responseHead.getCode())) {

            String resultOutputFilepath = responseBody.getOutputFilepath();

            byte[] pdf = responseBody.getPdf();
            System.out.println(pdf == null ? 0 : pdf.length);

            String resultPdfFileDataHash = responseBody.getPdfFileDataHash();
            log.info("resultPdfFileDataHash=" + resultPdfFileDataHash);

            if (StringUtil.isNotEmpty(resultOutputFilepath)) {
                log.info("文件已输出到：" + resultOutputFilepath);
            } else {
                resultOutputFilepath = outputFilePath + functionName + ".pdf";
                IoUtil.write(resultOutputFilepath, pdf);
                log.info("文件已输出到：" + resultOutputFilepath);
            }
            File outputFile = new File(outputFilePath + functionName + ".pdf");

            //去V8上传附件
            JSONObject jsonObject = fileUpload(functionName + ".pdf", outputFile);
            return jsonObject;
        } else {
            log.error(functionName + "  NG,Code:" + responseHead.getCode() + ",Message:" + responseHead.getMessage());
            //去V8上传附件
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("msg" , functionName + "  NG,Code:" + responseHead.getCode() + ",Message:" + responseHead.getMessage());
            return jsonObject;
        }
    }

    /**
     *
     * @Description: 构造机构章签章策略 使用 ：1-印章绑定的图片；
     * @return
     * @throws Exception
     * @return: SealStrategy
     */
    @Override
    public SealStrategy generateSealStrategy(String sealPerson) throws Exception {

        // 使用印章绑定图片签章
        String type = BaseConstants.SEAL_TYPE_SEAL;
        String sealCode = "yz001";
        String sealPassword = PwdEncryptUtil.encrypto("Cfca1234!");
        SealStrategy sealStrategy = new SealStrategy();

        sealStrategy.setSealInfo(type, sealCode, sealPassword);

        // 算法，非空
        String hashAlg = BaseConstants.HASHALG_SHA256;
        sealStrategy.setHashAlg(hashAlg);
        // 透明度，0-1.0f，默认1.0f,不透明
        String fillOpacity = "1";
        sealStrategy.setFillOpacity(fillOpacity);
        // 是否显示，默认1 显示
        String visible = "1";
        sealStrategy.setVisible(visible);
        //签章图片显示尺寸 单位毫米  默认为图片本身尺寸
        //签章图片显示尺寸，单位毫米；如果是圆形，则为半径实际尺寸；如果是矩形，则为较长的一边的实际尺寸；如果是不规则图形，则为较长的一边的实际尺寸

        //String displaySize = "30";

        //sealStrategy.setDisplaySize(displaySize);


      /*  // 业务码 businessCode ，businessCode为空，则不添加业务码，业务码相关属性都不需要设置 ;
        // 业务码内容
        String businessCode = "2020-12-22";
        // 业务码字体大小，默认12，可以为空
        String businessFontSize = "20";
        // 以图片底部为起点，向上占图片百分之多少的位置开始显示业务码，默认0.5；
        //textRectHeightPercent*imageHeight 不能小于 10
        String textRectHeightPercent = "0.5";
        // 颜色值，默认黑色 000000
        String businessColor = "000000";
        // 字体，默认宋体，可以为空
        String bussinessFamily = "SimSun-ExtB";
        // 业务码 end
        sealStrategy.setBusinessInfo(businessCode, businessFontSize, textRectHeightPercent, businessColor, bussinessFamily);
         */
        // 签章杂项信息
        // 签章人姓名，必填
        //String sealPerson = "王小薇";//sealPerson为 数据来源
        // 签章地点，可以为空
        String sealLocation = "北京朝阳";
        // 签章原因，可以为空
        String sealReason = "银行账户开立";
        sealStrategy.setSealMiscInfo(sealPerson, sealLocation, sealReason);


        // businessCode 业务码和图片下方增加日期不能同时添加，
        // 默认按照"yyyy年MM月dd日"日期格式添加当前日期，addDateText不为空时采用上送值添加到图片下方
       /* String addDateText = "";
        // 字体颜色，默认为黑色，可以为空
        String dateFontColor = "FF0000";
        // 字体，默认宋体，可以为空
        String dateFontFamily = "MicrosoftYaHei";
        // 字体大小，默认12，可以为空
        String dateFontSize = "8";
        // 在图片下方扩展的高度，默认40，可以为空;建议值：比字号的两倍大一些；最小值不能小于10，最大值不能高于图片的高度
        String dateRectHeight = "";
        sealStrategy.setAddDateTextInfo(dateFontColor, dateFontFamily, dateFontSize, dateRectHeight);   */

        /************************ 坐标签章 ****************************************************/
         // 签章页码
      /*   String page = "1";
        // x轴坐标
        String lx = "100";
        // y轴坐标
        String ly = "100";
        // 坐标签章
        sealStrategy.setSignWithCoordinate(page, lx, ly); */
        /*
        List<SignLocation> signLocationList = new ArrayList<SignLocation>();
        SignLocation signLocation1 = new SignLocation(page,lx,ly);
        signLocationList.add(signLocation1);
        SignLocation signLocation2 = new SignLocation("3",lx,ly);
        signLocationList.add(signLocation2);
        sealStrategy.setSignLocationList(signLocationList);*/

        /************************ 关键字签章 ****************************************************/
       //关键字
        String keyword ="四川发展（控股）有限责任公司";
        //x轴偏移，默认0
        String offSetX = "-10";
        //y轴偏移，默认0
        String offSetY = "10";

        String pageNo = "1";

        sealStrategy.setSignWithKeywordInfo(keyword, offSetX, offSetY);

        // sealStrategy.setPageNo("2");

       /* List<KeywordLocation> keywordLocationList = new ArrayList<KeywordLocation>();

        KeywordLocation keywordLocation1 = new KeywordLocation(pageNo,keyword,offSetX,offSetY);

        keyword = "个人账户";
        KeywordLocation keywordLocation2 = new KeywordLocation(keyword);

        keywordLocationList.add(keywordLocation1);
        keywordLocationList.add(keywordLocation2);

        sealStrategy.setKeywordLocationList(keywordLocationList);*/

        //sealStrategy.setKeywordPositionIndex("1");


        /************************ 空白域签章 ****************************************************/


           //空白域名称
      /*  String signatureFieldName = "SQR";
        sealStrategy.setSignWithBlankField(signatureFieldName); */

        return sealStrategy;
    }

    @Value("${cfca.v8openapi}")
    private String v8openapi;
    @Value("${cfca.v8ip}")
    private String v8ip;
    @Value("${cfca.appkey}")
    private String appkey;
    @Value("${cfca.appSecret}")
    private String appSecret;
    @Value("${cfca.fileUploadService}")
    private String fileUploadService;
    @Value("${cfca.outputFilePath}")
    private String outputFilePath;

    /**
     * V8附件下载
     * @return
     * @throws IOException
     */
    @Override
    public JSONObject fileDownload(String storageKey) {
        InputStream inputStream = null;
        JSONObject result = new JSONObject();
        String path = "/cip-manager/FileAppService/generateShareUrl";
        String url = v8openapi + path;
        try {
            Date date = new Date();
            long time = date.getTime();
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("data" , storageKey);
            jsonObject.put("requestId" , time);
            jsonObject.put("timestamp" , time);
            String md5String = MD5.getMD5String(appSecret + jsonObject.toString() + appSecret);

            Map<String, String> headers = new HashMap<>();
            headers.put("app-key", "769664d9edd049769b989d248c1db224");
            headers.put("sign-type", "MD5");
            headers.put("sign", md5String);
            headers.put("Content-Type", "application/json");
            String postBody = OkHttp3Util.post(jsonObject.toString(), headers, url);

            JSONObject resultJSON = JSONObject.parseObject(postBody);
            Integer status = resultJSON.getInteger("status");
            if (status == 0) {
                JSONObject data = resultJSON.getJSONObject("data");
                String content = data.getString("content");

                //String v8ip = v8Config.getV8ip();
                // 创建URL对象
                URL fileDownloadUrl = new URL(v8ip + "/service"+content);

                // 打开输入流
                inputStream = fileDownloadUrl.openStream();

                ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
                byte[] buffer = new byte[1024];
                int bytesRead;
                while ((bytesRead = inputStream.read(buffer)) != -1) {
                    byteArrayOutputStream.write(buffer, 0, bytesRead);
                }
                byte[] pdfByte = byteArrayOutputStream.toByteArray();
                result.put("pdfByte" , pdfByte);
            }else {
                log.error("v8上传附件失败:"+postBody);
                result.put("msg" , "v8上传附件失败:"+postBody);
            }
        }catch (Exception e){
            log.error("v8上传附件失败:",e);
            result.put("msg" , e);
            return result;
        } finally {
            try {
                if (inputStream != null){
                    inputStream.close();
                }
            } catch (IOException e) {
            }
        }
        return result;
    }

    /**
     * V8附件上传
     * @return
     * @throws IOException
     */
    @Override
    public JSONObject fileUpload(String functionName , File outputFile) throws IOException {
        JSONObject result = new JSONObject();
        String path = "/cip-manager/cip-common/file/upload";
        String url = v8openapi + path;

        Date date = new Date();
        long time = date.getTime();
        String sign = MD5.getMD5String(appSecret + time + appSecret);

        Map<String, String> headers = new HashMap<>();
        headers.put("app-key", appkey);
        headers.put("timestamp", time+"");
        headers.put("fileUploadService", fileUploadService);
        headers.put("sign", sign);
        headers.put("Content-Type", "application/json");

        RequestBody body = new MultipartBody.Builder().setType(MultipartBody.FORM)
                .addFormDataPart("file", functionName,RequestBody.create(MediaType.parse("application/octet-stream"),
                        outputFile))
                .build();

        // 创建OkHttpClient实例，设置连接超时时间和读取超时时间
        OkHttpClient client = new OkHttpClient.Builder()
                .connectTimeout(10, TimeUnit.SECONDS)
                .readTimeout(60, TimeUnit.SECONDS)
                .build();

        Request request = new Request.Builder()
                .url(url)
                .method("POST", body)
                .build();
        for (Map.Entry<String, String> entry : headers.entrySet()) {
            request = request.newBuilder().addHeader(entry.getKey(), entry.getValue()).build();
        }

        Response respSign = client.newCall(request).execute();
        String postBody = respSign.body().string();

        JSONObject resultJSON = JSONObject.parseObject(postBody);
        Integer status = resultJSON.getInteger("status");
        if (status == 0) {
            JSONObject data = resultJSON.getJSONObject("data");
            if (data == null){
                log.error("v8上传附件失败:"+postBody);
                result.put("msg" , "v8上传附件失败:"+postBody);
                return result;
            }
            JSONArray content = data.getJSONArray("content");
            String storageKey = content.getJSONObject(0).getString("storageKey");
            result.put("storageKey" , storageKey);
        }else {
            log.error("v8上传附件失败:"+postBody);
            result.put("msg" , "v8上传附件失败:"+postBody);
        }
        return result;
    }
}
